package com.example.demo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.dao.ParameterAttributeDao;
import com.example.demo.dao.ParameterDao;
import com.example.demo.dao.ParameterDefinitionDao;
import com.example.demo.dao.ParameterValueDao;
import com.example.demo.domain.conts.ConstDataType;
import com.example.demo.domain.entity.ParameterAttributeValueEntity;
import com.example.demo.domain.entity.ParameterDefinitionEntity;
import com.example.demo.domain.entity.ParameterEntity;
import com.example.demo.domain.entity.ParameterValueEntity;
import com.example.demo.domain.model.Parameter;
import com.example.demo.domain.model.ParameterAttributeValue;
import com.example.demo.domain.model.ParameterDefinition;
import com.example.demo.domain.model.ParameterValue;
import com.example.demo.domain.model.build.PavBuilder;
import com.example.demo.domain.model.build.PvBuilder;
import com.example.demo.domain.vo.front.PageWrapper;
import com.example.demo.domain.vo.front.ParameterDefinitionFormVO;
import com.example.demo.domain.vo.front.ParameterFrontVO;
import com.example.demo.service.ParameterDefinitionService;
import com.example.demo.service.ParameterFrontService;
import com.example.demo.service.ParameterService;
import com.example.demo.service.ParameterValueService;
import com.example.demo.util.PageWrapperUtil;
import com.example.demo.util.differe.ParameterDefinitionContainer;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ParameterFrontServiceImpl implements ParameterFrontService {

    @Autowired
    private ParameterDao parameterDao;
    @Autowired
    private ParameterValueDao parameterValueDao;
    @Autowired
    private ParameterDefinitionDao parameterDefinitionDao;
    @Autowired
    private ParameterAttributeDao parameterAttributeDao;

    @Autowired
    ParameterService parameterService;
    @Autowired
    ParameterDefinitionService parameterDefinitionService;
    @Autowired
    ParameterValueService parameterValueService;

    @Override
    public ParameterEntity getSingleP(Long id) {
        Assert.notNull(id, "ID 为空了");
        return parameterDao.selectById(id);
    }

    @Override
    public Long saveSingleP(Parameter parameter) {
        if (parameter.getId() != null) {
            parameterService.validateAndUpdateParameter(parameter);
        } else {
            parameterService.validateAndSaveParameter(parameter);
        }
        return parameter.getId();
    }

    @Override
    public void removeSingleP(Long id) {
        parameterService.deleteParameterById(id);
    }

    @Override
    public void removeSinglePD(Long id) {
        parameterDefinitionService.deleteById(id);
    }

    @Override
    public void removeSinglePV(Long id) {
        parameterValueService.deleteRelationshipById(id);
    }

    @Override
    public ParameterDefinitionEntity getSinglePd(Long id) {
        Assert.notNull(id, "id is null");
        return parameterDefinitionDao.selectById(id);
    }

    @Override
    public PageWrapper<ParameterFrontVO> getPage(Integer pageSize, Integer pageNumber, String code) {
        IPage<ParameterEntity> page = new Page<>(pageNumber, pageSize);
        LambdaQueryWrapper<ParameterEntity> wrapper = Wrappers.lambdaQuery(ParameterEntity.class);
        if (code != null && !"".equals(code.trim())) {
            wrapper.likeRight(ParameterEntity::getCode, code);
        }
        IPage<ParameterEntity> parameterEntityIPage = parameterDao.selectPage(page, wrapper);
        return PageWrapperUtil.build(parameterEntityIPage, this::getParameterFrontVOS);
    }

    @Override
    public List<ParameterDefinitionEntity> getPD(Long pid) {
        LambdaQueryWrapper<ParameterDefinitionEntity> pdWrapper = Wrappers.lambdaQuery(ParameterDefinitionEntity.class).eq(ParameterDefinitionEntity::getParentId, pid);
        return parameterDefinitionDao.selectList(pdWrapper);
    }

    @Override
    public Long saveSinglePD(ParameterDefinitionFormVO vo) {
        Parameter parameter = parameterService.getParameterById(vo.getParentId());
        ParameterDefinition parameterDefinition = new ParameterDefinition();
        BeanUtils.copyProperties(vo, parameterDefinition);
        if (vo.getId() != null) {
            parameter.setParameterDefinition(parameterDefinition);
        } else {
            parameter.addParameterDefinition(parameterDefinition);
        }
        parameterService.validateAndUpdateParameter(parameter);
        return parameterDefinition.getId();
    }

    @Override
    public PageWrapper<ParameterDefinitionEntity> pagePD(Integer pageSize, Integer pageNumber, Long pid) {
        IPage<ParameterDefinitionEntity> page = new Page<>(pageNumber, pageSize);

        LambdaQueryWrapper<ParameterDefinitionEntity> pdWrapper = Wrappers.lambdaQuery(ParameterDefinitionEntity.class).eq(ParameterDefinitionEntity::getParentId, pid);
        IPage<ParameterDefinitionEntity> parameterDefinitionEntityIPage = parameterDefinitionDao.selectPage(page, pdWrapper);
        return PageWrapperUtil.build(parameterDefinitionEntityIPage);
    }

    @Override
    public PageWrapper<Map<String, String>> getPvPage(Integer pageSize, Integer pageNumber, Long pid) {
        IPage<ParameterValueEntity> page = new Page<>(pageNumber, pageSize);
        LambdaQueryWrapper<ParameterValueEntity> wrapper = Wrappers.lambdaQuery(ParameterValueEntity.class);
        wrapper.eq(ParameterValueEntity::getParentId, pid);
        IPage<ParameterValueEntity> parameterValueEntityIPage = parameterValueDao.selectPage(page, wrapper);

        Map<String, ParameterDefinitionEntity> pdMap = getStringParameterDefinitionEntityMap(pid);

        return PageWrapperUtil.build(parameterValueEntityIPage, x -> getParameterValueFrontVOS(x, pdMap));
    }

    private Map<String, ParameterDefinitionEntity> getStringParameterDefinitionEntityMap(Long pid) {
        LambdaQueryWrapper<ParameterDefinitionEntity> pdWrapper = Wrappers.lambdaQuery(ParameterDefinitionEntity.class).eq(ParameterDefinitionEntity::getParentId, pid);
        List<ParameterDefinitionEntity> parameterDefinitionEntities = parameterDefinitionDao.selectList(pdWrapper);
        return parameterDefinitionEntities.stream().collect(Collectors.toMap(ParameterDefinitionEntity::getCode, ParameterDefinitionEntity -> ParameterDefinitionEntity));
    }

    @Override
    public Long saveSinglePv(Map<String, String> pv) {
        String name = pv.get("name");
        String code = pv.get("code");
        String pidstr = pv.get("parentId");

        Long pid = Long.parseLong(pidstr);


        Parameter parameter = parameterService.getParameterById(pid);

        List<ParameterDefinition> parameterDefinitions = parameter.getParameterDefinitions();
        //Optional<ParameterValue> first = parameter.getParameterValues().stream().filter(x -> x.getCode().equals(code)).findFirst();

        List<ParameterAttributeValue> attributeValues = new ArrayList<>();

        for (ParameterDefinition parameterDefinition : parameterDefinitions) {
            String pdname = parameterDefinition.getName();
            String pdCode = parameterDefinition.getCode();
            String pddatatype = parameterDefinition.getDatatype();
            // Sting
            if (ConstDataType.STRING.equals(pddatatype)) {
                String stringValue = pv.get(pdname);
                attributeValues.add(PavBuilder.apav().withStringValue(pdCode, stringValue).build());
            }
            // JSON LIST
            if (ConstDataType.JOSNLIST.equals(pddatatype)) {
                JSONArray objects = (JSONArray) JSON.toJSON(pv.get(pdname));
                attributeValues.add(PavBuilder.apav().withJOSNListValue(pdCode, objects.toJSONString()).build());
            }
        }
        ParameterValue parameterValue = PvBuilder.apv(name, code).withAttributeValues(attributeValues).build();

        String id = pv.get("id");
        if (id == null || "".equals(id)) {
            parameter.addParameterValue(parameterValue);
        } else {
            parameterValue.setId(Long.parseLong(id));
            parameter.setParameterValue(parameterValue);
        }
        parameterService.validateAndUpdateParameter(parameter);
        return parameterValue.getId();
    }

    public Long saveSinglePv2(Map<String, String> pv) {
        ParameterDefinitionContainer pContainer = new ParameterDefinitionContainer();
        return null;
    }

    @Override
    public Map<String, String> getPvById(Long pvid) {
        ParameterValueEntity parameterValueEntityIPage = parameterValueDao.selectById(pvid);
        Long pid = parameterValueEntityIPage.getParentId();
        Map<String, ParameterDefinitionEntity> pdMap = getStringParameterDefinitionEntityMap(pid);
        List<Map<String, String>> parameterValueFrontVOS = getParameterValueFrontVOS(Collections.singletonList(parameterValueEntityIPage), pdMap);
        if (!parameterValueFrontVOS.isEmpty()) {
            return parameterValueFrontVOS.get(0);
        }
        return null;
    }

    private List<Map<String, String>> getParameterValueFrontVOS(List<ParameterValueEntity> x, Map<String, ParameterDefinitionEntity> pdMap) {
        List<Map<String, String>> parameterFrontVOS = new ArrayList<>();
        x.forEach(z -> {
            Map<String, String> describe = new HashMap<>();
/*            try {
                describe = org.apache.commons.beanutils.BeanUtils.describe(z);
            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                e.printStackTrace();
            }
            if (describe == null) {
                return;
            }*/
            describe.put("id", String.valueOf(z.getId()));
            describe.put("name", z.getName());
            describe.put("code", z.getCode());
            LambdaQueryWrapper<ParameterAttributeValueEntity> paWrapper = Wrappers.lambdaQuery(ParameterAttributeValueEntity.class).eq(ParameterAttributeValueEntity::getParentId, z.getId());
            List<ParameterAttributeValueEntity> parameterAttributeValueEntities = parameterAttributeDao.selectList(paWrapper);
            for (ParameterAttributeValueEntity e : parameterAttributeValueEntities) {
                ParameterDefinitionEntity entity = pdMap.get(e.getAttributeCode());
                if (ConstDataType.STRING.equals(entity.getDatatype())) {
                    describe.put(entity.getName(), e.getStringValue());
                }
                if (ConstDataType.JOSNLIST.equals(entity.getDatatype())) {
                    describe.put(entity.getName(), e.getTextValue());
                }
            }

            parameterFrontVOS.add(describe);
        });
        return parameterFrontVOS;
    }

    private List<ParameterFrontVO> getParameterFrontVOS(List<ParameterEntity> x) {
        List<ParameterFrontVO> parameterFrontVOS = new ArrayList<>();
        x.forEach(z -> {
            ParameterFrontVO target = new ParameterFrontVO();
            BeanUtils.copyProperties(z, target);
            parameterFrontVOS.add(target);
        });
        return parameterFrontVOS;
    }
}
